
pub mod fnutils {

    use std::{thread, time::{Duration, SystemTime, UNIX_EPOCH}};

    use futures::Future;

    // 可以理解为这是Y组合子
    fn r<A, R>(g: impl Fn(&dyn Fn(A) -> R, A) -> R) -> impl Fn(A) -> R {
        fn r_inner<'a, A, R>(g: &'a dyn Fn(&dyn Fn(A) -> R, A) -> R) -> impl Fn(A) -> R + 'a {
            move |x| g(&r_inner(g), x)
        }
        move |x| r_inner(&g)(x)
    }

    pub fn current_ms() -> u128 {
        SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .unwrap()
            .as_millis()
    }

    pub fn wait_fn<T, R>(
        f: impl Fn(&T) -> Result<R, String>, 
        until_fn: impl Fn(&Result<R, String>) -> bool + 'static, 
        wait_ms: u32,
        interval_ms: u32
    ) -> impl Fn(T) -> Result<R, String> {
        let caller = move |next: &dyn Fn((T, u128)) -> Result<R, String>, (x, start_time): (T, u128)| {
            let result = f(&x);
            if until_fn(&result) {
                return result;
            }
            let end_time = current_ms();
            if end_time - start_time > (wait_ms as u128) {
                return Err("time out".to_string());
            }
            println!("等待中等待中");
            thread::sleep(Duration::from_millis(interval_ms as u64));
            next((x, start_time))
        };
        let f = r(caller);
        move |x: T| {
            f((x, current_ms()))
        }
    }


    #[cfg(test)]
    mod test {
        use super::wait_fn;

        #[test]
        #[should_panic(expected = "time out")]
        fn test_wait_fn() {
            let do_fn = |x: &u32| -> Result<u32, String> {
                println!("{}", x);
                Ok(*x)
            };
            let until_fn = |result: &Result<u32, String>| {
                let ss = result.to_owned().unwrap();
                if ss == 0 {
                    return false;
                }
                return true;
            };

            let new_fn = wait_fn(do_fn, until_fn, 60000, 500);

            new_fn(0).unwrap();
        }



        #[test]
        fn sss() {
            struct Func<'a, A, F>(&'a dyn Fn(Func<'a, A, F>, A) -> F);
    
            impl<'a, A, F> Clone for Func<'a, A, F> {
                fn clone(&self) -> Self {
                    Self(self.0)
                }
            }
    
            impl<'a, A, F> Copy for Func<'a, A, F> {}
    
            impl<'a, A, F> Func<'a, A, F> {
                fn call(&self, f: Func<'a, A, F>, x: A) -> F {
                    (self.0)(f, x)
                }
            }
    
            fn y<A, R>(g: impl Fn(&dyn Fn(A) -> R, A) -> R) -> impl Fn(A) -> R {
                move |x| (|f: Func<A, R>, x| f.call(f, x))(Func(&|f, x| g(&|x| f.call(f, x), x)), x)
            }
    
            let g = |f: &dyn Fn(usize) -> usize, x| match x {
                0 => 1,
                _ => x * f(x - 1),
            };

            let fact = y(g);
            println!("{}", fact(5)); // 将会输出 120
        }

        #[test]
        fn sss2() {
            fn r<A, R>(g: impl Fn(&dyn Fn(A) -> R, A) -> R) -> impl Fn(A) -> R {
                fn r_inner<'a, A, R>(g: &'a dyn Fn(&dyn Fn(A) -> R, A) -> R) -> impl Fn(A) -> R + 'a {
                    move |x| g(&r_inner(g), x)
                }
                move |x| r_inner(&g)(x)
            }
            
            let g = |f: &dyn Fn(usize) -> usize, x| match x {
                0 => 1,
                _ => x * f(x - 1),
            };
        
            let fact = r(g);
            println!("{}", fact(5)); // 将会输出 120
        }
    }


}
